#region Copyright (c) 2006-2009 Widgetsphere LLC, All Rights Reserved
//--------------------------------------------------------------------- *
//                          Widgetsphere  LLC                           *
//             Copyright (c) 2006-2009 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF WIDGETSPHERE LLC   *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS ANY WIDGETSPHERE PRODUCT.    *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF WIDGETSPHERE,      *
//INC.  THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO       *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion
using System;
using System.Collections;
using System.Xml;
using System.ComponentModel;
using Widgetsphere.Generator.Common.Util;
using Widgetsphere.Generator.Common.GeneratorFramework;

namespace Widgetsphere.Generator.Models
{
  public class CustomAggregateColumn : BaseModelObject, ICodeFacadeObject
  {
    #region Member Variables

    protected const System.Data.SqlDbType _def_type = System.Data.SqlDbType.VarChar;
    protected const int _def_length = 1;
    protected const bool _def_allowNull = true;
    protected const bool _def_generated = true;
    protected const int _def_sortOrder = 0;
    protected const bool _def_gridVisible = false;

    protected int _id = 0;
    protected string _name = "";
    protected string _codeFacade = "";
    protected string _description = "";
    protected System.Data.SqlDbType _type = _def_type;
    protected int _length = _def_length;
    protected bool _generated = _def_generated;
    protected bool _allowNull = _def_allowNull;
    protected string _default = "";
    protected Reference _parentViewRef = null;
    protected Reference _relationshipRef = null;
    protected string _friendlyName = "";
    protected int _sortOrder = _def_sortOrder;
    protected bool _gridVisible = _def_gridVisible;
    private string _enumType = "";

    #endregion

    #region Constructor

    public CustomAggregateColumn(IModelObject root)
      : base(root)
    {
    }

    #endregion

    #region Property Implementations

    [
    Browsable(true),
    Description("Should this customAggregateColumn be generated as part of the default table."),
    Category("Data"),
    DefaultValue(_def_generated),
    ]
    public bool Generated
    {
      get { return _generated; }
      set
      {
        _generated = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("generated"));
      }
    }

    [
    Browsable(true),
    Description("Determines the name of this column."),
    Category("Design"),
    DefaultValue(""),
    ]
    public string Name
    {
      get { return _name; }
      set
      {
        _name = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Name"));
      }
    }

    [
    Browsable(true),
    Description("Determines description text were applicable."),
    Category("Data"),
    DefaultValue(""),
    ]
    public string Description
    {
      get { return _description; }
      set
      {
        _description = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Description"));
      }
    }

    [Browsable(false)]
    public Reference RelationshipRef
    {
      get { return _relationshipRef; }
      set { _relationshipRef = value; }
    }

    [
    Browsable(true),
    Description("Determines the default value of this column."),
    Category("Data"),
    DefaultValue(""),
    ]
    public string Default
    {
      get { return _default; }
      set
      {
        _default = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Default"));
      }
    }

    [
    Browsable(true),
    Description("Determines the size in bytes of this column."),
    Category("Data"),
    DefaultValue(_def_length),
    ]
    public int Length
    {
      get
      {
        int retval = this.GetPredefinedSize();
        if(retval == -1)
          retval = _length;
        return retval;
      }
      set
      {
        if(value <= 0)
          value = 1;
        _length = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Length"));
      }
    }

    [Browsable(false)]
    public int Id
    {
      get { return _id; }
    }

    [Browsable(false)]
    public Reference ParentViewRef
    {
      get { return _parentViewRef; }
      set { _parentViewRef = value; }
    }

    [
    Browsable(true),
    Description("Determines the data type of this column."),
    Category("Data"),
    DefaultValue(System.Data.SqlDbType.VarChar),
    ]
    public System.Data.SqlDbType Type
    {
      get { return _type; }
      set
      {
        _type = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Type"));
      }
    }

    [
    Browsable(true),
    Description("Determines if this customAggregateColumn allows null values."),
    Category("Data"),
    DefaultValue(_def_allowNull),
    ]
    public bool AllowNull
    {
      get { return _allowNull; }
      set
      {
        _allowNull = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("allowNull"));
      }
    }

    /// <summary>
    /// Determines the header text shown to users, if this column is visible in data grid displays.
    /// </summary>
    [
    Browsable(true),
    Description("Determines the header text shown to users, if this column is visible in data grid displays."),
    Category("Appearance"),
    ]
    public string FriendlyName
    {
      get { return _friendlyName; }
      set
      {
        _friendlyName = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("friendlyName"));
      }
    }

    /// <summary>
    /// Determines the sort order of this field in relation to other data visible fields.
    /// </summary>
    [
    Browsable(true),
    Description("Determines the sort order of this field in relation to other data visible fields."),
    Category("Appearance"),
    DefaultValue(_def_sortOrder),
    ]
    public int SortOrder
    {
      get { return _sortOrder; }
      set
      {
        _sortOrder = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("sortOrder"));
      }
    }

    /// <summary>
    /// Determines if the column is visible in grids.
    /// </summary>
    [
    Browsable(true),
    Description("Determines if the column is visible in grids."),
    Category("Appearance"),
    DefaultValue(_def_gridVisible),
    ]
    public bool GridVisible
    {
      get { return _gridVisible; }
      set
      {
        _gridVisible = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("gridVisible"));
      }
    }

    internal string EnumType
    {
      get { return _enumType; }
      set { _enumType = value; }
    }

    internal string DatabaseType
    {
      get
      {
        string retval = this.Type.ToString();
        switch (this.Type)
        {
          case System.Data.SqlDbType.Char:
          case System.Data.SqlDbType.NChar:          
          case System.Data.SqlDbType.NVarChar:          
          case System.Data.SqlDbType.VarChar:
            retval += "(" + this.Length + ")"; ;
            break;
        }
        return retval;
      }
    }

    #endregion

    #region Methods

    public override string ToString()
    {
      string sizeString = "";
      if(this.GetPredefinedSize() == -1)
        sizeString = "(" + this.Length + ")";

      string retval = this.Name;
			//if(this.CodeFacade != "")
			//  retval += " AS " + this.CodeFacade;
			return retval;

      //retval += " (" + this.Type.ToString().ToLower() + sizeString + ", " + (this.AllowNull ? "Null" : "Not Null") + ")";
      //return retval;
    }

    #endregion

    #region IXMLable Members

    public override void XmlAppend(XmlNode node)
    {
      try
      {
        XmlDocument oDoc = node.OwnerDocument;

        XmlAttribute keyNode = oDoc.CreateAttribute("key");
        keyNode.Value = this.Key.ToString();
        node.Attributes.Append(keyNode);

        XmlHelper.AddAttribute((XmlElement)node, "generated", Generated.ToString());

        XmlAttribute name = oDoc.CreateAttribute("name");
        name.Value = this.Name;
        node.Attributes.Append(name);

        XmlAttribute codefacade = oDoc.CreateAttribute("codeFacade");
        codefacade.Value = this.CodeFacade;
        node.Attributes.Append(codefacade);

        XmlAttribute description = oDoc.CreateAttribute("description");
        description.Value = this.Description;
        node.Attributes.Append(description);

        XmlAttribute dataFieldFriendlyName = oDoc.CreateAttribute("dataFieldFriendlyName");
        dataFieldFriendlyName.Value = this.FriendlyName;
        node.Attributes.Append(dataFieldFriendlyName);

        XmlAttribute dataFieldVisibility = oDoc.CreateAttribute("dataFieldVisibility");
        dataFieldVisibility.Value = this.GridVisible.ToString();
        node.Attributes.Append(dataFieldVisibility);

        XmlAttribute dataFieldSortOrder = oDoc.CreateAttribute("dataFieldSortOrder");
        dataFieldSortOrder.Value = this.SortOrder.ToString();
        node.Attributes.Append(dataFieldSortOrder);

        if(RelationshipRef != null)
        {
          XmlNode relationshipRefNode = oDoc.CreateElement("relationshipRef");
          RelationshipRef.XmlAppend(relationshipRefNode);
          node.AppendChild(relationshipRefNode);
        }

        XmlAttribute defaultVal = oDoc.CreateAttribute("default");
        defaultVal.Value = this.Default;
        node.Attributes.Append(defaultVal);

        XmlAttribute length = oDoc.CreateAttribute("length");
        length.Value = this.Length.ToString();
        node.Attributes.Append(length);

        XmlAttribute id = oDoc.CreateAttribute("id");
        id.Value = this.Id.ToString();
        node.Attributes.Append(id);

        XmlAttribute sortOrder = oDoc.CreateAttribute("sortOrder");
        sortOrder.Value = this.SortOrder.ToString();
        node.Attributes.Append(sortOrder);

        XmlNode parentViewRefNode = oDoc.CreateElement("parentTableRef");
        ParentViewRef.XmlAppend(parentViewRefNode);
        node.AppendChild(parentViewRefNode);

        XmlAttribute type = oDoc.CreateAttribute("type");
        type.Value = this.Type.ToString("d");
        node.Attributes.Append(type);

        XmlAttribute allowNull = oDoc.CreateAttribute("allowNull");
        allowNull.Value = this.AllowNull.ToString();
        node.Attributes.Append(allowNull);

      }
      catch(Exception ex)
      {
        throw;
      }
    }

    public override void XmlLoad(XmlNode node)
    {
      try
      {
        _key = XmlHelper.GetAttributeValue(node, "key", _key);
        this.Generated = bool.Parse(XmlHelper.GetAttributeValue(node, "generated", _def_generated.ToString()));
        this.Name = node.Attributes["name"].Value;
        this.CodeFacade = XmlHelper.GetAttributeValue(node, "codeFacade", "");
        this.Description = node.Attributes["description"].Value;
        this.FriendlyName = XmlHelper.GetAttributeValue(node, "dataFieldFriendlyName", this.FriendlyName);
        this.GridVisible = bool.Parse(XmlHelper.GetAttributeValue(node, "dataFieldVisibility", this.GridVisible.ToString()));
        this.SortOrder = int.Parse(XmlHelper.GetAttributeValue(node, "dataFieldSortOrder", this.SortOrder.ToString()));
        XmlNode relationshipRefNode = node.SelectSingleNode("relationshipRef");
        if(relationshipRefNode != null)
        {
          RelationshipRef = new Reference(this.Root);
          RelationshipRef.XmlLoad(relationshipRefNode);
        }

        this.Default = node.Attributes["default"].Value;
        this.Length = int.Parse(node.Attributes["length"].Value);
        this.SetId(int.Parse(node.Attributes["id"].Value));

        XmlNode parentViewRefNode = node.SelectSingleNode("parentTableRef");
        ParentViewRef = new Reference(this.Root);
        if (parentViewRefNode != null)
          ParentViewRef.XmlLoad(parentViewRefNode);

        string typeString = node.Attributes["type"].Value;
        if(typeString != "")
          this.Type = (System.Data.SqlDbType)int.Parse(typeString);

        this.AllowNull = bool.Parse(XmlHelper.GetAttributeValue(node, "allowNull", "false"));

        this.Dirty = false;
      }
      catch(Exception ex)
      {
        throw;
      }

    }

    #endregion

    #region Helpers

    public Reference CreateRef()
    {
      Reference returnVal = new Reference(this.Root);
      returnVal.Ref = this.Id;
      returnVal.RefType = ReferenceType.CustomAggregateColumn;
      return returnVal;
    }

    [Browsable(false)]
    public string CamelName
    {
			//get { return StringHelper.DatabaseNameToCamelCase(this.Name); }
			get { return StringHelper.DatabaseNameToCamelCase(this.PascalName); }
		}

    [Browsable(false)]
    public string PascalName
    {
			get
			{
				if (this.CodeFacade != "")
					return StringHelper.DatabaseNameToPascalCase(this.CodeFacade);
				else
					return StringHelper.DatabaseNameToPascalCase(this.Name);
			}
		}

    [Browsable(false)]
    public string DatabaseName
    {
      get { return this.Name; }
    }

		public string GetCodeType()
		{
			return GetCodeType(true, false);
		}

		public string GetCodeType(bool allowNullable)
		{
			return GetCodeType(allowNullable, false);
		}

		public string GetCodeType(bool allowNullable, bool forceNull)
		{
			string retval = "";
			if (this.EnumType != "")
			{
				retval = this.EnumType;
			}
			else if (StringHelper.Match(this.Type.ToString(), "bigint", true))
			{
				retval = "long";
			}
			else if (StringHelper.Match(this.Type.ToString(), "binary", true))
			{
				return "System.Byte[]";
			}
			else if (StringHelper.Match(this.Type.ToString(), "bit", true))
			{
				retval = "bool";
			}
			else if (StringHelper.Match(this.Type.ToString(), "char", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.Type.ToString(), "datetime", true))
			{
				retval = "DateTime";
			}
			else if (StringHelper.Match(this.Type.ToString(), "decimal", true))
			{
				retval = "decimal";
			}
			else if (StringHelper.Match(this.Type.ToString(), "float", true))
			{
				retval = "double";
			}
			else if (StringHelper.Match(this.Type.ToString(), "image", true))
			{
				return "System.Byte[]";
			}
			else if (StringHelper.Match(this.Type.ToString(), "int", true))
			{
				retval = "int";
			}
			else if (StringHelper.Match(this.Type.ToString(), "money", true))
			{
				retval = "decimal";
			}
			else if (StringHelper.Match(this.Type.ToString(), "nchar", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.Type.ToString(), "ntext", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.Type.ToString(), "numeric", true))
			{
				retval = "decimal";
			}
			else if (StringHelper.Match(this.Type.ToString(), "nvarchar", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.Type.ToString(), "real", true))
			{
				retval = "System.Single";
			}
			else if (StringHelper.Match(this.Type.ToString(), "smalldatetime", true))
			{
				retval = "DateTime";
			}
			else if (StringHelper.Match(this.Type.ToString(), "smallint", true))
			{
				retval = "short";
			}
			else if (StringHelper.Match(this.Type.ToString(), "smallmoney", true))
			{
				retval = "decimal";
			}
			else if (StringHelper.Match(this.Type.ToString(), "variant", true))
			{
				retval = "object";
			}
			else if (StringHelper.Match(this.Type.ToString(), "text", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.Type.ToString(), "tinyint", true))
			{
				retval = "byte";
			}
			else if (StringHelper.Match(this.Type.ToString(), "uniqueidentifier", true))
			{
				retval = "System.Guid";
			}
			else if (StringHelper.Match(this.Type.ToString(), "varbinary", true))
			{
				return "System.Byte[]";
			}
			else if (StringHelper.Match(this.Type.ToString(), "varchar", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.Type.ToString(), "timestamp", true))
			{
				return "System.Byte[]";
			}
			else
			{
				throw new Exception("Cannot Map Sql Value To C# Value");
			}

			if (allowNullable && (this.AllowNull || forceNull))
				retval += "?";

			return retval;

		}

    /// <summary>
    /// Determines if the Datatype suppors the 'Parse' method
    /// </summary>
    [Browsable(false)]
    public bool AllowStringParse
    {
      get
      {
        if(StringHelper.Match(this.Type.ToString(), "bigint", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "binary", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "bit", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "char", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "datetime", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "decimal", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "float", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "image", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "int", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "money", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "nchar", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "ntext", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "numeric", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "nvarchar", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "real", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "smalldatetime", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "smallint", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "smallmoney", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.Type.ToString(), "variant", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "text", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "tinyint", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "uniqueidentifier", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "varbinary", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "varchar", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.Type.ToString(), "timestamp", true))
        {
          return false;
        }
        else
        {
          return false;
        }
      }
    }

    protected internal void SetId(int id)
    {
      _id = id;
    }

    private int GetPredefinedSize()
    {
      //Returns -1 if variable
      switch(this.Type)
      {
        case System.Data.SqlDbType.BigInt:
          return 8;
        case System.Data.SqlDbType.Bit:
          return 1;
        case System.Data.SqlDbType.DateTime:
          return 8;
        case System.Data.SqlDbType.Decimal:
          return 13;
        case System.Data.SqlDbType.Float:
          return 8;
        case System.Data.SqlDbType.Int:
          return 4;
        case System.Data.SqlDbType.Money:
          return 8;
        case System.Data.SqlDbType.Real:
          return 4;
        case System.Data.SqlDbType.SmallDateTime:
          return 4;
        case System.Data.SqlDbType.SmallInt:
          return 2;
        case System.Data.SqlDbType.SmallMoney:
          return 4;
        case System.Data.SqlDbType.Timestamp:
          return 8;
        case System.Data.SqlDbType.TinyInt:
          return 1;
        case System.Data.SqlDbType.UniqueIdentifier:
          return 16;
        default:
          return -1;
      }
    }

    #endregion

    #region ICodeFacadeObject Members

    [
    Browsable(true),
    Description("Determines the object name used in the API. If this property is blank the 'Name' property is used in the API. This property can be used to mask the database identifier."),
    Category("Design"),
    DefaultValue(""),
    ]
    public string CodeFacade
    {
      get { return _codeFacade; }
      set
      {
        _codeFacade = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("codeFacade"));
      }
    }

    public string GetCodeFacade()
    {
      if(this.CodeFacade == "")
        return this.Name;
      else
        return this.CodeFacade;
    }

    #endregion

  }
}